package com.yixing.tech.entity.utils;

import com.yixing.tech.common.base.BusinessException;
import com.yixing.tech.common.enums.ErrCode;
import com.yixing.tech.common.utils.DataUtil;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.nfunk.jep.JEP;
import org.nfunk.jep.Node;
import org.nfunk.jep.ParseException;
import org.nfunk.jep.function.PostfixMathCommand;
import org.springframework.util.ObjectUtils;

import java.util.*;

/**
 * @author yixing tech
 * @description: 表达式解析计算
 * @version: 1.0
 **/
@Slf4j
public  class ExpressionUtil {

    public static  void a() {
        String hexString= "55 17 10 02 00000751334941594C6E4C30310100";
        int len = hexString.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        int checkSum = 0;
        len = data.length;
        for (int pos = 0; pos < len; pos++) {
            checkSum += data[pos];
        }
        System.out.println(Integer.toHexString(checkSum & 0xFF));
//        return Integer.toHexString(checkSum & 0xFF);
    }
    public static void main(String... arg) {
//       a();
        String formula = "a!=\"b\"";
        Object s = null;
        Map map = new HashMap();
        map.put("a", "c");
        try {
            s = evaluate(map, formula);
            System.out.println(s);
        } catch (BusinessException e) {
            e.printStackTrace();
        }
    }
    //16进制字符串转byte数组
    public static byte[] Hex2Byte(String inHex) {

        String[] hex=inHex.split(" ");//将接收的字符串按空格分割成数组
        byte[] byteArray=new byte[hex.length];

        for(int i=0;i<hex.length;i++) {
            //parseInt()方法用于将字符串参数作为有符号的n进制整数进行解析
            byteArray[i]=(byte)Integer.parseInt(hex[i],16);
        }

        return byteArray;

    }
    /**
     * 动态配置公式方式
     *
     * @param map
     * @param formulaExpr
     */
    public static Object evaluate(Map map, String formulaExpr) throws BusinessException {
        JEP jep = getJEP(map);
        return evaluateJep(jep, formulaExpr);
    }

    /**
     * 动态配置公式方式
     *
     * @param map
     * @param formulaExpr
     */
    public static boolean evaluateCondition(Map map, String formulaExpr) throws BusinessException {
        JEP jep = getJEP(map);
        return evaluateCondition(jep, formulaExpr);
    }


    /**
     * 判断条件表达式
     *
     * @param jep
     * @param expression
     * @return
     */
    private static boolean evaluateCondition(JEP jep, String expression) throws BusinessException {
        if (jep.hasError()) {
            return false;
        }
        return (Double) evaluateJep(jep, expression) > 0;
    }

    /**
     * 计算表达式的值
     *
     * @param jep
     * @param expression
     * @return
     */
    private static Object evaluateJep(JEP jep, String expression) throws BusinessException {
        Object result;
        try {
            result = jep.evaluate(jep.parse(expression));
        } catch (ParseException e) {
            e.printStackTrace();
            throw new BusinessException(ErrCode.PARAMETER_ERROR, e.getErrorInfo());
        }
        if (result == null) {
            throw new BusinessException(ErrCode.PARAMETER_ERROR);
        }
        return result;
    }

    /**
     * 获取填充好变量的JEP对象
     *
     * @param param
     * @return
     */
    private static JEP getJEP(Map param) {
        JEP jep = new JEP();
        jep.addFunction("range", new Range());
        jep.addFunction("rangeJudge", new RangeJudge());
        jep.addFunction("lastChar", new LastChar());
        jep.addFunction("arraySum", new ArraySum());
        jep.addStandardFunctions();
        jep.addStandardConstants();
        jep.addComplex();
        Set<Map.Entry> set = param.entrySet();
        for (Map.Entry entry : set) {
            Object entryValue = entry.getValue();
            String entryKey = (String) entry.getKey();
            jep.addVariable(entryKey, entryValue==null?"":DataUtil.isNumeric(entryValue)?Double.parseDouble(entryValue.toString()):entryValue);
        }
        return jep;
    }

    /**
     * 极差
     */
    static class Range extends PostfixMathCommand {
        Range() {
            super.numberOfParameters = -1;
        }

        @Override
        public void run(Stack s) throws ParseException {
            checkStack(s);

            List<Double> list = new ArrayList<>();
            while (!s.empty()) {
                list.add(Double.valueOf(s.pop().toString()));
            }
            //排序
            Collections.sort(list);
            double r = 0;

            if (list.size() > 1)
                //max - min
                r = list.get(list.size() - 1) - list.get(0);

            else r = 0;

            if (r < 0) r = 0;

            s.push(r);
        }
    }

    /**
     * 集合遍历累加
     */
    static class ArraySum extends PostfixMathCommand {
        ArraySum() {
            super.numberOfParameters = -1;
        }
        @Override
        public void run(Stack s) throws ParseException {
            checkStack(s);
            double sum = 0;
            String code = s.pop().toString();
            List<Map> list = (List<Map>) s.pop();
            for(Map doc:list){
                sum+=Double.valueOf(ObjectUtils.isEmpty(doc.get(code))?"0":doc.get(code).toString());
            }
            s.push(sum);
        }
    }
    /**
     * 范围判断
     */
    static class RangeJudge extends PostfixMathCommand {
        RangeJudge() {
            super.numberOfParameters = -1;
        }

        @Override
        public void run(Stack s) throws ParseException {
            checkStack(s);

           Object v = s.pop().toString();
           String c = s.pop().toString();

           if(ObjectUtils.isEmpty(v)||ObjectUtils.isEmpty(c)){
               s.push(0);
               return;
           }

           if(!c.contains("±")){
               s.push(1);
               return;
           }

           String[] c1 = c.split("±");
            if(c1.length<2){
                s.push(1);
                return;
            }
            try {
                Double t = Double.parseDouble(c1[0].trim());
                Double r = Double.parseDouble(c1[1].trim());
                double min = t-r;
                double max = t+r;
                Double vd = Double.parseDouble(v.toString().trim());
                s.push(vd>=min&&vd<=max?1:0);

            }catch (Exception e){
                s.push(1);
            }
        }
    }
    /**
     * 范围判断
     */
    static class LastChar extends PostfixMathCommand {
        LastChar() {
            super.numberOfParameters = 1;
        }

        @Override
        public void run(Stack s) throws ParseException {
            checkStack(s);

            String v = s.pop().toString();
            log.error("------LastChar---------:"+v);
            if(ObjectUtils.isEmpty(v)){
                s.push("");
                return;
            }
            String r = v.substring(v.length()-1);
            s.push(r);

        }
    }
}



